﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using FasterWPF.Selectors;
using FasterWPF.Observables;
//using Xceed.Wpf.DataGrid;

namespace FasterWPF.Observables
{
    public static class ObservableHelper
    {
        public static IObservable<EventPattern<TEventArgs>> AddExtraObservableFromBorder<TEventArgs, K, T>(this Border composite, int row, int column, string eventName)
            where K : UIElement
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {

            IObservable<EventPattern<TEventArgs>> observableToReturn = Observable.FromEventPattern<TEventArgs>(composite.GetChildFromComposite<K, T>(row, column), eventName);

            return observableToReturn;
        }

        #region GetObservables

        /// <summary>
        /// Get an Observable from a Child at row-column with eventName from a Composite (Border)
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="composite"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static IObservable<EventPattern<TEventArgs>> GetObservableFromBorder<TEventArgs>(this Border composite, int row, int column, string eventName)
            where TEventArgs : System.EventArgs
        {
            string key = composite.GetKey();
            string row_col = "_" + row + "_" + column;
            string suffixKey = row_col + key;

            string fullKey = eventName + suffixKey;

            Dictionary<string, IDisposable> iDispDictry = composite.GetDisposablesDictionaryFromBorder();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(fullKey, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName-row-column-key combination!");
            }

            IObservable<EventPattern<TEventArgs>> observableToReturn = null;
            observableToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).ObservableObject as IObservable<EventPattern<TEventArgs>>);

            return observableToReturn;
        }

        /// <summary>
        /// Get an Observable from a Child at key-row-column with eventName from a Parent
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static IObservable<EventPattern<TEventArgs>> GetObservableFromParent<TEventArgs, T>(this T parent, string key,  int row, int column, string eventName)
            where T: FrameworkElement
            where TEventArgs : System.EventArgs
        {
            string row_col = "_" + row + "_" + column;
            string suffixKey = row_col + key;

            string fullKey = eventName + suffixKey;

            Dictionary<string, IDisposable> iDispDictry = parent.GetCompositeFromParent(key).GetDisposablesDictionaryFromBorder();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(fullKey, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName-row-column-key combination!");
            }

            IObservable<EventPattern<TEventArgs>> observableToReturn = null;
            observableToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).ObservableObject as IObservable<EventPattern<TEventArgs>>);

            return observableToReturn;
        }

        /// <summary>
        /// Get an Observable from a parent with eventName
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static IObservable<EventPattern<TEventArgs>> GetObservableFromParent<TEventArgs, T>(this T parent, string eventName)
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {

            Dictionary<string, IDisposable> iDispDictry = parent.GetDisposablesDictionary<T>();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(eventName, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName!");
            }

            IObservable<EventPattern<TEventArgs>> observableToReturn = null;
            observableToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).ObservableObject as IObservable<EventPattern<TEventArgs>>);

            return observableToReturn;
        }

        #endregion

        #region GetSubjects

        /// <summary>
        /// Get a Subject from a Child at row-column with eventName from a Composite (Border)
        /// </summary>
        /// <param name="composite"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static object GetSubjectFromBorder(this Border composite, int row, int column, string eventName)
        {
            string key = composite.GetKey();
            string row_col = "_" + row + "_" + column;
            string suffixKey = row_col + key;

            string fullKey = eventName + suffixKey;

            Dictionary<string, IDisposable> iDispDictry = composite.GetDisposablesDictionaryFromBorder();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(fullKey, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName-row-column-key combination!");
            }

            object actionToReturn = null;
            actionToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).SubjectDelegate as object);

            return actionToReturn;
        }

        /// <summary>
        /// Get a Subject from a Child at key-row-column with eventName from a Parent
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static object GetSubjectFromParent<T>(this T source, string key, int row, int column, string eventName)
            where T : FrameworkElement
        {
            string row_col = "_" + row + "_" + column;
            string suffixKey = row_col + key;

            string fullKey = eventName + suffixKey;

            Dictionary<string, IDisposable> iDispDictry = source.GetDisposablesDictionary();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(fullKey, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName-row-column-key combination!");
            }

            object actionToReturn = null;
            actionToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).SubjectDelegate as object);

            return actionToReturn;
        }

        #endregion

        #region FireObservables

        /// <summary>
        /// Fire an Observable from a Child at key-row-column with eventName and eventArgs from a Parent. Find the Parent via Selector Class name (first traversing up then down)
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="startingSource"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="maxNumParentsToGoUpToGetWindow"></param>
        /// <param name="nameOfWindowType"></param>
        /// <param name="parentClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservableByClassName<TEventArgs>(this FrameworkElement startingSource, string key, int row, int column, int maxNumParentsToGoUpToGetWindow,  string nameOfWindowType, string parentClassName, string eventName, TEventArgs eventArgs)
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            Window mainWindow = Selectors.Select.RecurseUpParentFrameworkElementsUntilType(false, maxNumParentsToGoUpToGetWindow, startingSource, nameOfWindowType) as Window;
            FrameworkElement myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as FrameworkElement;
            UIElement myChild = myBrder.GetChildFromParent<UIElement, FrameworkElement>(key, row, column);

            Subject<EventPattern<TEventArgs>> eventSubj3 = FasterWPF.Observables.ObservableHelper.GetSubjectFromParent<FrameworkElement>(myBrder, key, row, column, eventName) as Subject<EventPattern<TEventArgs>>;

            eventSubj3.OnNext(new EventPattern<TEventArgs>(myChild, eventArgs));
        }

        /// <summary>
        /// Fire an Observable from a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (first traversing up then down)
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="startingSource"></param>
        /// <param name="maxNumParentsToGoUpToGetWindow"></param>
        /// <param name="nameOfWindowType"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservableByClassName<TEventArgs>(this FrameworkElement startingSource, int maxNumParentsToGoUpToGetWindow, string nameOfWindowType, string parentClassName, string childClassName, string eventName, TEventArgs eventArgs)
    where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            Window mainWindow = Selectors.Select.RecurseUpParentFrameworkElementsUntilType(false, maxNumParentsToGoUpToGetWindow, startingSource, nameOfWindowType) as Window;
            FrameworkElement myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as FrameworkElement;
            FrameworkElement myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as FrameworkElement;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }

            Subject<EventPattern<TEventArgs>> eventSubj3 = FasterWPF.Observables.ObservableHelper.GetSubjectFromParent<FrameworkElement>(myBrder, myKey, row, column, eventName) as Subject<EventPattern<TEventArgs>>;

            eventSubj3.OnNext(new EventPattern<TEventArgs>(myChild, eventArgs));
        }

        /// <summary>
        /// Fire an Observable from a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="startingSource"></param>
        /// <param name="maxNumParentsToGoUpToGetWindow"></param>
        /// <param name="nameOfWindowType"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservableByClassName<TEventArgs>(this Window mainWindow, string parentClassName, string childClassName, string eventName, TEventArgs eventArgs)
    where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            FrameworkElement myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as FrameworkElement;
            FrameworkElement myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as FrameworkElement;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }

            Subject<EventPattern<TEventArgs>> eventSubj3 = FasterWPF.Observables.ObservableHelper.GetSubjectFromParent<FrameworkElement>(myBrder, myKey, row, column, eventName) as Subject<EventPattern<TEventArgs>>;

            eventSubj3.OnNext(new EventPattern<TEventArgs>(myChild, eventArgs));
        }

        /// <summary>
        /// Fire an Observable from a Child at row-column with eventName and eventArgs from a Composite (Border) and a Parent T
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="composite"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservable<TEventArgs, T>(this T parent, Border composite, int row, int column, string eventName, TEventArgs eventArgs)
          where T: FrameworkElement
          where TEventArgs : System.EventArgs
        {
            Subject<EventPattern<TEventArgs>> eventSubj = (Subject<EventPattern<TEventArgs>>)composite.GetSubjectFromBorder(row, column, eventName);
            eventSubj.OnNext(new EventPattern<TEventArgs>(parent.GetTextBlock<T>(composite.GetKey().ToString(), row, column), eventArgs));
        }

        /// <summary>
        /// Fire an Observable from a Child at key-row-column with eventName and eventArgs from a Parent T
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservable<TEventArgs, T>(this T parent, string key, int row, int column, string eventName, TEventArgs eventArgs)
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            Subject<EventPattern<TEventArgs>> eventSubj = (Subject<EventPattern<TEventArgs>>)parent.GetCompositeFromParent<T>(key).GetSubjectFromBorder(row, column, eventName);
            eventSubj.OnNext(new EventPattern<TEventArgs>(parent.GetTextBlock<T>(key, row, column), eventArgs));
        }

        /// <summary>
        /// Fire an Observable that exists on a parent T with eventName and eventArgs
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservableOnParent<TEventArgs, T>(this T parent, string eventName, TEventArgs eventArgs)
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {

            Dictionary<string, IDisposable> iDispDictry = parent.GetDisposablesDictionary<T>();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(eventName, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName!");
            }

            Subject<EventPattern<TEventArgs>> actionToReturn = null;
            actionToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).SubjectDelegate as Subject<EventPattern<TEventArgs>>);
            
            actionToReturn.OnNext(new EventPattern<TEventArgs>(parent, eventArgs));
        }

        /// <summary>
        /// Fire an Observable that exists on a parent T with eventName and eventArgs. Find the Parent via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireObservableOnParent<TEventArgs, T>(this Window mainWindow, string parentClassName, string eventName, TEventArgs eventArgs)
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            T parent = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            Dictionary<string, IDisposable> iDispDictry = parent.GetDisposablesDictionary<T>();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(eventName, out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName!");
            }

            Subject<EventPattern<TEventArgs>> actionToReturn = null;
            actionToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).SubjectDelegate as Subject<EventPattern<TEventArgs>>);
            
            actionToReturn.OnNext(new EventPattern<TEventArgs>(parent, eventArgs));
        }

        /// <summary>
        /// Fire a Mouse Single Click Observable that exists on a parent T with eventName and eventArgs. Find the Parent via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="eventName"></param>
        /// <param name="eventArgs"></param>
        public static void FireSingleClickOnParent<T>(this Window mainWindow, string parentClassName, MouseButtonEventArgs eventArgs)
            where T : FrameworkElement
        {
            T parent = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            Dictionary<string, IDisposable> iDispDictry = parent.GetDisposablesDictionary<T>();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue("PreviewMouseDown", out idisp))
            {
                throw new Exception("Cannot retrieve Observable. No existing Observable found by that eventName!");
            }

            Subject<EventPattern<MouseButtonEventArgs>> actionToReturn = null;
            actionToReturn = ((idisp as FasterWPF.CommonExt.ObservableDisposer).SubjectDelegate as Subject<EventPattern<MouseButtonEventArgs>>);

            actionToReturn.OnNext(new EventPattern<MouseButtonEventArgs>(parent, eventArgs));
        }
        #endregion

        #region SubscribeObservables

        /// <summary>
        /// Subscribe a Mouse Single Click Observable to a Parent with eventName and eventArgs. Find the Parent via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="mainWindow"></param>
        /// <param name="parentClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeSingleClickOnParent<T>(this Window mainWindow, string parentClassName, Action<EventPattern<MouseButtonEventArgs>> actionDelegate)
            where T : FrameworkElement
        {
            //Start from top-level: Window
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;

            myBrder.SubscribeEventOnParent<T, MouseButtonEventArgs>("PreviewMouseDown", actionDelegate);
        }

        /// <summary>
        /// Subscribe an Observable to a Parent with eventName and eventArgs. Find the Parent via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="mainWindow"></param>
        /// <param name="parentClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeObservableOnParent<T, TEventArgs>(this Window mainWindow, string parentClassName, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;

            myBrder.SubscribeEventOnParent<T, TEventArgs>(eventName, actionDelegate); 
        }
        
        /// <summary>
        /// Subscribe a Connectable Observable to a Parent with eventName and eventArgs. Find the Parent via Selector Class names (traversing down from Window). Signature for connectable is: (connectableObservable, actionDelegate).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="mainWindow"></param>
        /// <param name="parentClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeObservableOnParent<T, TEventArgs>(this Window mainWindow, string parentClassName, string eventName, Action<EventPattern<TEventArgs>> actionDelegate, Action<IConnectableObservable<EventPattern<TEventArgs>>, Action<EventPattern<TEventArgs>>> composeObservable)
            where T : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;

            myBrder.SubscribeEventOnParent<T, TEventArgs>(eventName, actionDelegate, composeObservable);
        }

        /// <summary>
        /// Subscribe an Observable to a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (first traversing up then down)
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="startingSource"></param>
        /// <param name="maxNumParentsToGoUpToGetWindow"></param>
        /// <param name="nameOfWindowType"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeObservableByClassName<K, T, TEventArgs>(this FrameworkElement startingSource, int maxNumParentsToGoUpToGetWindow, string nameOfWindowType, string parentClassName, string childClassName, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            Window mainWindow = Selectors.Select.RecurseUpParentFrameworkElementsUntilType(false, maxNumParentsToGoUpToGetWindow, startingSource, nameOfWindowType) as Window;
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            K myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as K;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }

            FasterWPF.CommonExt.SubscribeEventOnChild<K, T, TEventArgs>(myBrder, myChild, myKey, row, column, eventName, actionDelegate);
        }

        /// <summary>
        /// Subscribe an Observable to a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="mainWindow"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeObservableByClassName<K, T, TEventArgs>(this Window mainWindow, string parentClassName, string childClassName, string eventName, Action<EventPattern<TEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            K myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as K;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }

            FasterWPF.CommonExt.SubscribeEventOnChild<K, T, TEventArgs>(myBrder, myChild, myKey, row, column, eventName, actionDelegate);
        }

        /// <summary>
        /// Subscribe a Dependency Event Observable to a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (first traversing up then down)
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="startingSource"></param>
        /// <param name="maxNumParentsToGoUpToGetWindow"></param>
        /// <param name="nameOfWindowType"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeDepEventByClassName<K, T, TEventArgs>(this FrameworkElement startingSource, int maxNumParentsToGoUpToGetWindow, string nameOfWindowType, string parentClassName, string childClassName, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            Window mainWindow = Selectors.Select.RecurseUpParentFrameworkElementsUntilType(false, maxNumParentsToGoUpToGetWindow, startingSource, nameOfWindowType) as Window;
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            K myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as K;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }

            FasterWPF.CommonExt.SubscribeDependencyEventOnChild<K, T>(myBrder, myChild, myKey, row, column, eventName, actionDelegate);
        }

        /// <summary>
        ///  Subscribe a Dependency Event Observable to a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (traversing down from Window)
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="mainWindow"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeDepEventByClassName<K, T, TEventArgs>(this Window mainWindow, string parentClassName, string childClassName, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            K myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as K;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }
            FasterWPF.CommonExt.SubscribeDependencyEventOnChild<K, T>(myBrder, myChild, myKey, row, column, eventName, actionDelegate);
        }
        
        /// <summary>
        ///  Subscribe a Dependency Event Observable to a Child with eventName and eventArgs from a Parent. Find the Parent and Child (First matching) via Selector Class names (traversing down from Window). Signature for connectable is: (connectableObservable, actionDelegate).
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TEventArgs"></typeparam>
        /// <param name="mainWindow"></param>
        /// <param name="parentClassName"></param>
        /// <param name="childClassName"></param>
        /// <param name="eventName"></param>
        /// <param name="actionDelegate"></param>
        public static void SubscribeDepEventByClassName<K, T, TEventArgs>(this Window mainWindow, string parentClassName, string childClassName, string eventName, Action<EventPattern<ValueChangedEventArgs>> actionDelegate, Action<IConnectableObservable<EventPattern<ValueChangedEventArgs>>, Action<EventPattern<ValueChangedEventArgs>>> composeObservable)
            where T : FrameworkElement
            where K : FrameworkElement
            where TEventArgs : System.EventArgs
        {
            //Start from top-level: Window
            T myBrder = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false).First() as T;
            K myChild = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false).First() as K;

            string myKey = null;
            string[] parsedValues = null;
            int row = 0;
            int column = 0;
            char myChar = '_';
            var myDict = myBrder.GetChildLookupDictionary();
            foreach (KeyValuePair<string, object> keyValPair in myDict)
            {
                if (keyValPair.Value == myChild)
                {
                    parsedValues = keyValPair.Key.Split(myChar);
                    myKey = parsedValues[0];
                    row = Int32.Parse(parsedValues[1]);
                    column = Int32.Parse(parsedValues[2]);
                }
            }
            FasterWPF.CommonExt.SubscribeDependencyEventOnChild<K, T>(myBrder, myChild, myKey, row, column, eventName, actionDelegate, composeObservable);
        }

        #endregion

        #region Guards

        public static bool CanGetSubjectFromParent<T>(this T source, string key, int row, int column, string eventName)
           where T : FrameworkElement
        {
            bool canGet = true;
            string row_col = "_" + row + "_" + column;
            string suffixKey = row_col + key;

            string fullKey = eventName + suffixKey;

            Dictionary<string, IDisposable> iDispDictry = source.GetDisposablesDictionary();

            IDisposable idisp = null;
            if (!iDispDictry.TryGetValue(fullKey, out idisp))
            {
                canGet = false;
            }

            return canGet;
        }

         public static bool IsObservableAvailableByClassName<TEventArgs>(this FrameworkElement startingSource, int maxNumParentsToGoUpToGetWindow, string nameOfWindowType, string parentClassName, string childClassName, string eventName)
        {
            bool isAvailable = true;

            //Start from top-level: Window
            Window mainWindow = Selectors.Select.RecurseUpParentFrameworkElementsUntilType(false, maxNumParentsToGoUpToGetWindow, startingSource, nameOfWindowType) as Window;

            var a = mainWindow.SelectAllFrameworkElementsByClass(parentClassName, false);
           
            if (a!= null && a.Count>0)
            {
                FrameworkElement myBrder = a.First() as FrameworkElement;

                var b = mainWindow.SelectAllFrameworkElementsByClass(childClassName, false);

                if (b != null && b.Count > 0)
                {
                    FrameworkElement myChild = b.First() as FrameworkElement;
                    string myKey = null;
                    string[] parsedValues = null;
                    int row = 0;
                    int column = 0;
                    char myChar = '_';
                    var myDict = myBrder.GetChildLookupDictionary();
                    foreach (KeyValuePair<string, object> keyValPair in myDict)
                    {
                        if (keyValPair.Value == myChild)
                        {
                            parsedValues = keyValPair.Key.Split(myChar);
                            myKey = parsedValues[0];
                            row = Int32.Parse(parsedValues[1]);
                            column = Int32.Parse(parsedValues[2]);
                        }
                    }

                    isAvailable = FasterWPF.Observables.ObservableHelper.CanGetSubjectFromParent<FrameworkElement>(myBrder, myKey, row, column, eventName);
                }
                else
                {
                    isAvailable = false;
                }
            }
            else
            {
                isAvailable = false;
            }
            return isAvailable;
        }
       #endregion                
    }
}//end of namespace
